package mastermind.gui.controls;

import java.util.ArrayList;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;

/**
 * Diese Klasse stellt einen Button im Mastermind Design dar
 */
public class ButtonUI extends Composite
{
	private String						_text		= "";
	private int							_state		= 0;		// 0=Normal;
																// 1=Hover;
																// 2=Pressed
	private boolean						_isPressed	= false;
	private RGB[]						_colBorder;
	private RGB[]						_colBackground;
	private RGB[]						_colText;
	private ArrayList<SelectionAdapter>	_listener;
	private boolean						_pressed;

	/**
	 * Erstellt ein neues ButtonUI Objekt
	 * 
	 * @param parent
	 *            Eltern-Objekt, auf das das ButtonUI Objekt plaziert wird
	 * @param style
	 *            Zus&auml;zliche Style Informationen
	 */
	public ButtonUI(Composite parent, int style)
	{
		super(parent, style);
		_listener = new ArrayList<SelectionAdapter>();
		_colBorder = new RGB[] { new RGB(150, 75, 0), new RGB(100, 60, 0), new RGB(60, 30, 0), new RGB(60, 30, 0) };
		_colBackground = new RGB[] { new RGB(230, 170, 130), new RGB(240, 190, 160), new RGB(200, 130, 90), new RGB(200, 130, 90) };
		_colText = new RGB[] { new RGB(110, 60, 0), new RGB(100, 60, 0), new RGB(60, 30, 0), new RGB(60, 30, 0) };

		// Events
		// Das Element neu zeichnen, wenn angefordert
		this.addPaintListener(new PaintListener() {
			@Override
			public void paintControl(PaintEvent e)
			{
				if (isDisposed())
					return;
				e.gc.setAntialias(SWT.ON);

				e.gc.setBackground(new Color(Display.getDefault(), _colBackground[isEnabled() && !_pressed ? _state : 3]));
				e.gc.fillRoundRectangle(1, 1, getBounds().width - 2, getBounds().height - 2, 7, 7);

				e.gc.setLineWidth(2);
				e.gc.setForeground(new Color(Display.getDefault(), _colBorder[isEnabled() && !_pressed ? _state : 3]));
				e.gc.drawRoundRectangle(1, 1, getBounds().width - 2, getBounds().height - 2, 7, 7);

				e.gc.setForeground(new Color(Display.getDefault(), _colText[isEnabled() && !_pressed ? _state : 3]));
				Point txtSize = e.gc.textExtent(_text);
				e.gc.drawText(_text, (getBounds().width - txtSize.x) / 2, (getBounds().height - txtSize.y) / 2);
			}
		});

		// Maus Klick Ereignisse verarbeiten
		this.addMouseListener(new MouseListener() {
			@Override
			public void mouseUp(MouseEvent e)
			{
				if (isDisposed())
					return;
				if (e.x < 0 || e.y < 0 || e.x > getBounds().width || e.y > getBounds().height)
				{
					_state = 0;
				}
				else
				{
					_state = 1;
					for (SelectionAdapter sel : _listener)
					{
						Event ev = new Event();
						ev.x = e.x;
						ev.y = e.y;
						ev.widget = e.widget;
						sel.widgetSelected(new SelectionEvent(ev));
					}
				}
				_isPressed = false;
				if (!isDisposed())
					redraw();
			}

			@Override
			public void mouseDown(MouseEvent e)
			{
				_isPressed = true;
				_state = 2;
				if (!isDisposed())
					redraw();
			}

			@Override
			public void mouseDoubleClick(MouseEvent e)
			{}
		});

		// Mouse Track Ereignisse verarbeiten
		this.addMouseTrackListener(new MouseTrackListener() {

			@Override
			public void mouseHover(MouseEvent e)
			{}

			@Override
			public void mouseExit(MouseEvent e)
			{
				if (isDisposed())
					return;
				if (_state == 0)
					return;

				_state = 0;
				if (!isDisposed())
					redraw();
			}

			@Override
			public void mouseEnter(MouseEvent e)
			{
				if (isDisposed())
					return;
				if (_state == 1)
					return;

				_state = 1;
				if (!isDisposed())
					redraw();
			}
		});

		// Mouse Move Ereignisse verarbeiten
		this.addMouseMoveListener(new MouseMoveListener() {

			@Override
			public void mouseMove(MouseEvent e)
			{
				if (isDisposed())
					return;
				if (e.button == 0)
					return;

				if (e.x < 0 || e.y < 0 || e.x > getBounds().width || e.y > getBounds().height)
				{
					if (_state == 0)
						return;
					_state = 0;
				}
				else
				{
					if (_state == (_isPressed ? 2 : 1))
						return;
					_state = (_isPressed ? 2 : 1);
				}
				if (!isDisposed())
					redraw();
			}
		});
	}

	/**
	 * Setzt den angegebenen Text als Buttonbeschriftung
	 * 
	 * @param text
	 *            Text der auf dem Button stehen soll
	 */
	public void setText(String text)
	{
		this._text = text;
	}

	/**
	 * Einen SelectionAdapter zur Liste hinzuf&uuml;gen, um bei einem Klick auf
	 * den Button benachrichtigt zu werden.
	 * 
	 * @param selectionAdapter
	 *            SelectionAdapter der auf den Klick reagieren soll
	 */
	public void addSelectionListener(SelectionAdapter selectionAdapter)
	{
		_listener.add(selectionAdapter);
	}

	/**
	 * Aktiviert, oder deaktiviert den Button
	 * 
	 * @param enabled
	 * <br/>
	 *            <code>true</code>, wenn der Button aktiviert werden soll<br/>
	 *            <code>false</code> sonst
	 */
	@Override
	public void setEnabled(boolean enabled)
	{
		super.setEnabled(enabled);
		if (!isDisposed())
			redraw();
	}

	/**
	 * Setzt den Zustand des Buttons um eine Checkbox Funktionalit&auml;t zu
	 * erm&ouml;glichen
	 * 
	 * @param state
	 */
	public void setPressed(boolean state)
	{
		_pressed = state;
	}
}
